package com.tiancheng.trade.payment.util;

import com.alibaba.excel.EasyExcel;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.WorkbookUtil;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@Slf4j
public final class ExcelBuildUtil {

    /**
     * 根据list生成excel
     */
    public static void mapToExcel(List<List<String>> head, List<List<Object>> data, HttpServletResponse response) throws IOException {
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename=data.xlsx");
        EasyExcel.write(response.getOutputStream()).head(head).sheet("sheet1").doWrite(data);
    }

    /**
     * 向Workbook中添加sheet
     *
     * @param workbook   {@link Workbook} 工作簿
     * @param sheetName  {@link String}   工作表名字
     * @param sheetTile  String[]         工作表表头
     * @param sheetData  {@link List}     工作表数据
     * @param isAutoSize boolean          是否自动调整列宽
     */
    public static void addSheet(Workbook workbook, String sheetName, String[] sheetTile, List<Map<String, Object>> sheetData, boolean isAutoSize) {
        Sheet sheet = workbook.createSheet(WorkbookUtil.createSafeSheetName(sheetName));
        int rowIndex = 0;
        int cellIndex = 0;
        if (sheetTile != null) {
            Row firstRow = sheet.createRow(rowIndex);
            for (String str : sheetTile) {
                firstRow.createCell(cellIndex).setCellValue(str);
                cellIndex++;
            }
        }

        if (sheetData == null || sheetData.isEmpty()) return;

        for (Map<String, Object> dataRow : sheetData) {
            rowIndex++;
            Row row = sheet.createRow(rowIndex);
            cellIndex = 0;
            for (Map.Entry<String, Object> dataCell : dataRow.entrySet()) {
                row.createCell(cellIndex).setCellValue(dataCell.getValue() == null ? "" : dataCell.getValue().toString());
                cellIndex++;
            }
        }
        if (isAutoSize) {
            try {
                autoSizeColumn(sheet, cellIndex);
            } catch (Exception ignored) {
            }
        }
    }

    /**
     * 自动调整列宽
     *
     * @param sheet     {@link Sheet} 工作表
     * @param maxColumn {@link Integer} 列数
     * @throws {@link Exception}
     */
    private static void autoSizeColumn(Sheet sheet, Integer maxColumn) throws Exception {
        //列宽自适应，只对英文和数字有效
        for (int i = 0; i <= maxColumn; i++) {
            sheet.autoSizeColumn(i);
        }
        //获取当前列的宽度，然后对比本列的长度，取最大值
        for (int columnNum = 0; columnNum <= maxColumn; columnNum++) {
            int columnWidth = sheet.getColumnWidth(columnNum) / 256;
            for (int rowNum = 0; rowNum <= sheet.getLastRowNum(); rowNum++) {
                Row currentRow;
                //当前行未被使用过
                if (sheet.getRow(rowNum) == null) {
                    currentRow = sheet.createRow(rowNum);
                } else {
                    currentRow = sheet.getRow(rowNum);
                }

                if (currentRow.getCell(columnNum) != null) {
                    int length = currentRow.getCell(columnNum).toString().getBytes("GBK").length;
                    if (columnWidth < length + 1) {
                        columnWidth = length + 1;
                    }
                }
            }
            int width = columnWidth * 256;
            if (width < 255 * 256) {
                sheet.setColumnWidth(columnNum, width);
            } else {
                sheet.setColumnWidth(columnNum, 255 * 256 - 1);
            }
        }
    }

    /**
     * 导出excel压缩包
     *
     * @param request   {@link HttpServletRequest}
     * @param response  {@link HttpServletResponse}
     * @param workbooks {@link Map} 工作簿名-工作簿 集合
     * @param zipName   {@link String} 压缩包名
     * @throws {@link IOException}
     */
    public static void exportExcelZip(HttpServletRequest request, HttpServletResponse response, Map<String, Workbook> workbooks, String zipName) throws IOException {
        //解决不同浏览器中文乱码问题
        String userAgent = request.getHeaders("User-Agent").nextElement().toLowerCase();
        if (userAgent.contains("msie") || userAgent.contains("like gecko")) {
            zipName = URLEncoder.encode(zipName, "UTF-8");
        } else {
            zipName = new String(zipName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
        }
        response.setContentType("application/octet-stream");
        response.setHeader("Connection", "close"); // 表示不能用浏览器直接打开
        response.setHeader("Accept-Ranges", "bytes");// 告诉客户端允许断点续传多线程连接下载
        response.setHeader("Content-Disposition", "attachment;filename=" + zipName);
        response.setCharacterEncoding("UTF-8");

        ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream());

        for (Map.Entry<String, Workbook> entry : workbooks.entrySet()) {
            zipOutputStream.putNextEntry(new ZipEntry(entry.getKey() + ".xlsx"));
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            entry.getValue().write(bos);
            bos.writeTo(zipOutputStream);
            //清除临时文件
            try {
                ((SXSSFWorkbook) entry.getValue()).dispose();
            }catch (Exception e){
                e.printStackTrace();
                log.warn("清理excel临时文件异常：{}",e.getMessage());
            }
        }
        zipOutputStream.flush();
        zipOutputStream.close();
        response.getOutputStream().close();
    }

    /**
     * 导出excel
     *
     * @param request  {@link HttpServletRequest}
     * @param response {@link HttpServletResponse}
     * @param workbook {@link Workbook} 工作簿
     * @param fileName {@link String} 工作簿名
     * @throws {@link IOException}
     */
    public static void exportExcel(HttpServletRequest request, HttpServletResponse response, Workbook workbook, String fileName) throws IOException {
        //解决不同浏览器中文乱码问题
        String userAgent = request.getHeaders("User-Agent").nextElement().toLowerCase();
        if (userAgent.contains("msie") || userAgent.contains("like gecko")) {
            fileName = URLEncoder.encode(fileName, "UTF-8");
        } else {
            fileName = new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
        }
        response.setHeader("Content-Disposition", "attachment;fileName=" + fileName);
        response.setContentType("application/force-download");
        workbook.write(response.getOutputStream());
        //清除临时文件
        try {
            ((SXSSFWorkbook) workbook).dispose();
        }catch (Exception e){
            e.printStackTrace();
            log.warn("清理excel临时文件异常：{}",e.getMessage());
        }

    }

}
